package sy6_Behavioral_Pattern.observer;
/*
 * 观察者模式（Observer Pattern）研究观察目标和观察者两类对象之间的关系
 * 角色1：抽象观察者Observer
 * 角色2：观察目标Subject（被观察者） 
 * 角色3：具体观察者ConcreateObserver
 * 角色4：具体目标ConcreateSubject
 * 要点如下：
 * （1）Subject定义了抽象方法attach(Observer observer)和detach(Observer observer)，用以维系若干Observer对象集合。
 * （2）Subject还定义了普通方法notifyToAll()，它包含了对Observer对象的调用，即存在Subject到Observer的关联关系。
 * （3）ConcreateObserver除了需要重写基类的抽象方法，还定义了表示观察到目标状态的属性observerState。
 *      其中，重写基类的抽象方法时使用了ConcreateSubject对象，这表明ConcreateObserver与ConcreateSubject之间的关联。
 * （4）ConcreateSubject除了需要重写基类的抽象方法，还定义了表示自身状态的属性subjectState。
 */
import java.util.ArrayList;
import java.util.List;

abstract class Observer{  //抽象观察者
	//public abstract void  update(Subject subject); //更新观察到的消息
	public abstract void  update(); //更新观察到的消息，无参，
}

abstract class Subject{  //目标
	//维系若干观察者，体现Subject对Observer的关联
	private List<Observer> observers=new ArrayList<>();
	
	public List<Observer> getObservers() {
		return observers;
	}

	public void notifyToAll() { //发通知
		for (Observer observer : observers) {
			observer.update(); 
		}
	}
	
	public abstract void attach(Observer observer);   //附加
	public abstract void detach(Observer observer);  //移除
}

class ConcreteObserver extends Observer{   //具体观察者
	private String name;  //观察者名称
	private String observerState;  //观察到的状态
	private Subject subject;  //体现对ConcreateSubject的关联
	
	public ConcreteObserver(String name, Subject subject) {  //有参构造方法
		this.name = name;
		this.subject=subject;
	}

	@Override
	public void update() {
		observerState=((ConcreteSubject)subject).getSubjectState();
		System.out.println(name+"收到通知："+observerState);
	}
}

class ConcreteSubject extends Subject{   //具体目标

	private String subjectState;  //目标状态
	
	public String getSubjectState() {
		return subjectState;
	}
	public void setSubjectState(String subjectState) {
		this.subjectState = subjectState;
	}
	
	@Override
	public void attach(Observer observer) { 
		getObservers().add(observer);
	}
	@Override
	public void detach(Observer observer) {  
		getObservers().remove(observer);
	}
}

public class Client {
	public static void main(String[] args) {
		//创建一个观察目标
		Subject subject = new ConcreteSubject();
		//创建观察者
		ConcreteObserver observer1 = new ConcreteObserver("张三",subject);
		ConcreteObserver observer2 = new ConcreteObserver("李四",subject);
		ConcreteObserver observer3 = new ConcreteObserver("王五",subject);
		//添加观察者到观察目标
		subject.attach(observer1);
		subject.attach(observer2);
		subject.attach(observer3);
		//观察目标设置状态
		((ConcreteSubject)subject).setSubjectState("明天下午考设计模式！");
		//观察目标发布通知
		subject.notifyToAll();
		
		System.out.println("==============================");
		subject.detach(observer3);  //删除一个观察者
		//观察目标更改状态
		((ConcreteSubject)subject).setSubjectState("后天上午考Java EE！");
		//观察目标发布通知
		subject.notifyToAll();
	}
}
